//
//  MKUIAnimation.m
//  MKUI
//
//  Created by 苏尚进 on 2025/6/23.
//  Copyright © 2025 moon. All rights reserved.
//

#import "MKUIAnimation.h"
#import <QuartzCore/QuartzCore.h>
@interface MKUIAnimation()
@property(nonatomic,assign) BOOL isAnimation;//是否动画中
@property(nonatomic,strong,nullable) CADisplayLink *displayLink;
@property(nonatomic,strong) NSDate *startTime;
@end

@implementation MKUIAnimation
- (id)init{
    if(self=[super init]){
        self.repeatCount = 1;
    }
    return self;
}
//- (void)dealloc{
//    NSLog(@"deallocMKUIAnimation:%@",self);
//}
- (void)setRepeatCount:(NSInteger)repeatCount{
    if(self.isAnimation)return;
    _repeatCount = repeatCount;
}
- (void)setDuration:(NSTimeInterval)duration{
    if(self.isAnimation)return;
    _duration = duration;
}
- (void)setDelay:(NSTimeInterval)delay{
    if(self.isAnimation)return;
    _delay = delay;
}
- (void)setAnimationsBlock:(void (^)(CGFloat))animationsBlock{
    if(self.isAnimation)return;
    _animationsBlock = animationsBlock;
}
- (void)setEasingFunction:(MKUIAnimationEasingFunction)easingFunction{
    if(self.isAnimation)return;
    _easingFunction = easingFunction;
}
- (void)setAutoreverse:(BOOL)autoreverse{
    if(self.isAnimation)return;
    _autoreverse = autoreverse;
}

- (void)beginAnimation{
    if(self.isAnimation)return;
    if(self.duration<0) return;
    self.isAnimation = YES;
    self.startTime = NSDate.date;
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tickAnimations)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];//滚动时也会触发
}
- (void)cancelAnimation{
    if(!self.isAnimation)return;
    [self endAnimation:NO];
}
- (void)endAnimation:(BOOL)finished{
    self.isAnimation = NO;
    [self.displayLink invalidate];
    self.displayLink = nil;
    if(self.completionBlock){
        self.completionBlock(finished);
    }
}
#pragma mark - private
- (void)tickAnimations{
    NSTimeInterval usingTime = [NSDate.date timeIntervalSinceDate:self.startTime];
    if(self.delay>usingTime) return;//延迟开始
    NSTimeInterval playedTime = usingTime-self.delay;
    CGFloat totolPercent = playedTime/self.duration;
    
    NSUInteger hadRepeatCount = (NSUInteger)totolPercent;
    NSUInteger leftCount = self.repeatCount<=0?NSUIntegerMax:self.repeatCount-hadRepeatCount;
    CGFloat percent = totolPercent-hadRepeatCount;//单次的进度
    if(leftCount==0){
        percent = 1;
    }
    if(self.autoreverse){
        if(percent>0.5){
            percent = 1-(percent*2-1);
        }else{
            percent *= 2;
        }
    }
    percent = MAX(0.0,MIN(1.0,percent));
    CGFloat progress = percent;
    if(self.easingFunction){//进行缓动效果
        progress = self.easingFunction(percent);
    }
//    NSLog(@"percent:%.5f,progress:%.5f",percent,progress);
    if(self.animationsBlock){
        self.animationsBlock(progress);
    }
    BOOL end = self.repeatCount>0&&hadRepeatCount>=self.repeatCount;
    if(end){//结束任务
        [self endAnimation:YES];
    }
}
@end

@implementation MKUIAnimationEasingObject
- (CGFloat)baseInFunction:(CGFloat)p{
    return p;
}
- (MKUIAnimationEasingFunction)In{
    return ^CGFloat (CGFloat p){
        return [self baseInFunction:p];
    };
}
- (MKUIAnimationEasingFunction)Out{
    return ^CGFloat (CGFloat p){
        return 1-[self baseInFunction:(1-p)];
    };
}
- (MKUIAnimationEasingFunction)InOut{
    return ^CGFloat (CGFloat p){
        return p<0.5?[self baseInFunction:p]:(1-[self baseInFunction:(1-p)]);
    };
}
- (MKUIAnimationEasingFunction)OutIn{
    return ^CGFloat (CGFloat p){
        return p<0.5?(1-[self baseInFunction:(1-p)]):[self baseInFunction:p];
    };
}
@end
@implementation MKUIAnimationEasingLiner
- (CGFloat)baseInFunction:(CGFloat)p{
    return p;
}
+ (instancetype)Function{
    return [[self alloc] init];
}
@end
@implementation MKUIAnimationEasingPower
- (CGFloat)baseInFunction:(CGFloat)p{
    return pow(p, self.power);
}
+ (MKUIAnimationEasingPower *(^)(NSInteger power))Function{
    return ^MKUIAnimationEasingPower *(NSInteger power){
        MKUIAnimationEasingPower *obj = [[MKUIAnimationEasingPower alloc] init];
        obj.power = power;
        return obj;
    };
}
@end
@implementation MKUIAnimationEasingExponential
- (CGFloat)baseInFunction:(CGFloat)p{//y=2^(10(x-1))
    return pow(2,10*(p-1));
}
+ (instancetype)Function{
    return [[self alloc] init];
}
@end
@implementation MKUIAnimationEasingBack
- (CGFloat)baseInFunction:(CGFloat)p{//x^3-x*sin(x*pi)
    return p*p*p-p*sin(p*M_PI);
}
+ (instancetype)Function{
    return [[self alloc] init];
}
@end

@implementation MKUIAnimationEasingBounce
- (id)init{
    if(self=[super init]){
        self.bounceCount = 2;
    }
    return self;
}
+ (instancetype)functionWithBounceCount:(NSInteger)bounceCount{
    MKUIAnimationEasingBounce *obj = [[self alloc] init];
    obj.bounceCount = bounceCount;
    return obj;
}
- (CGFloat)baseInFunction:(CGFloat)p{//y=-A*e^(-d*x)*cos(n*PI*x+0.5*PI)
    CGFloat A = 1.4;//值越大，最大振幅越大
    CGFloat d = 1.5;//值越小，振荡越剧烈
    CGFloat n = self.bounceCount;
    CGFloat r = -A*exp(-d*p)*cos(n*M_PI*p+M_PI_2);
    if(!self.oscillate){
        r = ABS(r);
    }
    return r;
}
@end
